package main

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"golang.org/x/crypto/ssh"
)

type Cli struct {
	IP         string      //IP地址
	Username   string      //用户名
	Password   string      //密码
	Port       int         //端口号
	client     *ssh.Client //ssh客户端
	LastResult string      //最近一次Run的结果
}

// 信令数据结构
type LogEntry struct {
	Timestamp   string `json:"timestamp"`
	SourceIP    string `json:"sourceIP"`
	TargetIP    string `json:"targetIP"`
	Protocol    string `json:"protocol"`
	Length      string `json:"length"`
	Description string `json:"description"`
}
// 图像数据结构
type DataResponse struct {  
	Times  []string `json:"times"`  
	Values []float64 `json:"values"`  
}  

// var buf1 []uint8

// 创建命令行对象
// @param ip IP地址
// @param username 用户名
// @param password 密码
// @param port 端口号,默认22
func New(ip string, username string, password string, port ...int) *Cli {
	cli := new(Cli)
	cli.IP = ip
	cli.Username = username
	cli.Password = password
	if len(port) <= 0 {
		cli.Port = 22
	} else {
		cli.Port = port[0]
	}
	return cli
}

// @param shell shell脚本命令
func (c Cli) Run1(shell string) (string, error) {
	if c.client == nil {
		if err := c.connect(); err != nil {
			//连接失败
			return "fail", err
		}
	}
	session, err := c.client.NewSession()
	if err != nil {
		return "fail", err
	}
	defer session.Close()
	buf, err := session.CombinedOutput(shell)
	c.LastResult = string(buf)
	// fmt.Println("正在运行获取Info")
	return c.LastResult, err
}

// 连接
func (c *Cli) connect() error {
	config := ssh.ClientConfig{
		User: c.Username,
		Auth: []ssh.AuthMethod{ssh.Password(c.Password)},
		HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
			return nil
		},
		Timeout: 10 * time.Second,
	}
	addr := fmt.Sprintf("%s:%d", c.IP, c.Port)
	sshClient, err := ssh.Dial("tcp", addr, &config)
	if err != nil {
		return err
	}
	c.client = sshClient
	return nil
}

// 解决跨域问题
func Cors() gin.HandlerFunc {
	return func(context *gin.Context) {
		method := context.Request.Method

		context.Header("Access-Control-Allow-Origin", "*")
		context.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token, x-token")
		context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH, PUT")
		context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type")
		context.Header("Access-Control-Allow-Credentials", "true")

		if method == "OPTIONS" {
			context.AbortWithStatus(http.StatusNoContent)
		}
	}
}

// 信令处理
func handleSignaling(output string) string {
	lines := strings.Split(output, "\n")
	// 使用正则表达式进行匹配
	r := regexp.MustCompile(`(\S+)\s+(\S+)\s+→\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)`)
	var LogEntries []LogEntry
	for _, line := range lines {
		match := r.FindStringSubmatch(line)
		if match != nil {
			entry := LogEntry{
				Timestamp:   match[1][:8],
				SourceIP:    match[2],
				TargetIP:    match[3],
				Protocol:    match[4],
				Length:      match[5],
				Description: match[6],
			}
			LogEntries = append(LogEntries, entry)
		}
	}
	// 将解析后的数据转换为JSON格式
	jsonData, err := json.Marshal(LogEntries)
	if err != nil {
		fmt.Println("Error marshaling JSON:", err)
	}
	return string(jsonData)
}

// 读取CSV文件并返回两个切片：时间切片和数据切片  
func readCSV(filename string) ([]string, []float64, error) {
	var times []string  
	var values []float64  

	file, err := os.Open(filename)  
	if err != nil {  
		return nil, nil, err  
	}  
	defer file.Close()  

	reader := csv.NewReader(file)  
	for {  
		record, err := reader.Read()  
		if err != nil {  
			if err == csv.ErrFieldCount {  
				continue // 忽略字段数量不匹配的记录  
			}  
			break // 读取结束或发生错误  
		}  

		// 假设时间已经是字符串格式，数据是浮点数  
		times = append(times, record[0])  
		value, err := parseFloat(record[1]) // 这里可能需要一个辅助函数来解析字符串为浮点数  
		if err != nil {  
			return nil, nil, err  
		}  
		values = append(values, value)  
	}  

	return times, values, nil  
}  

// 辅助函数：将字符串解析为浮点数  
func parseFloat(s string) (float64, error) {  
	return strconv.ParseFloat(s, 64) // 注意：需要导入"strconv"包  
}  

func main() {
	edge := New("10.112.38.20", "node", "a", 2222)
	ubuntuDefaultString := New("10.112.38.20", "node", "a", 2222)
	weixingServer := New("10.112.186.60", "weixingzu", "404bupt!", 2222)

	// Default返回一个默认的路由引擎
	r := gin.Default()
	r.Use(Cors())

	// 智能感知模块日志
	r.GET("/perceive", func(c *gin.Context) {
		// cmdStr1 := "kubectl get po -nfree5gc --kubeconfig=/home/node/.kube/config/admin.conf | grep amf"
		// output1, _ := edge.Run1(cmdStr1)
		// if output1 != "" {
		// 	cmdStr2 := "kubectl get po -nfree5gc --kubeconfig=/home/node/.kube/config/admin.conf | grep amf | awk '{print $1}' | xargs -i kubectl logs -n free5gc {} ephemeris --tail=2 --kubeconfig=/home/node/.kube/config/admin.conf"
		// 	// cmdStr2 := `kubectl get po -nfree5gc | grep amf | awk '{print $1}' | xargs -i kubectl exec -nfree5gc {} -c  ephemeris -- bash -c 'cat e.log'`
		// 	output2, _ := edge.Run1(cmdStr2)
		// 	// fmt.Println(output2)
		// 	c.String(200, "%v", output2)
		// } else {
		// 	c.String(200, "%v", "")
		// }
		cmdStr := `powershell -command "& {Get-Content D:\weixingzu\files\View3\rightdown.csv}"`
		output, _ := weixingServer.Run1(cmdStr)
		c.String(200, "%v", output)
	})
	r.GET("/perceive/result", func(c *gin.Context) {
		cmdStr := `powershell -command "& {Get-Content D:\weixingzu\files\View3\leftdowndown.csv}"`
		output, _ := weixingServer.Run1(cmdStr)
		c.String(200, "%v", output)
	})

	// 智能感知模块日志1
	r.GET("/perceive1", func(c *gin.Context) {
		cmdStr1 := "kubectl get po -nfree5gc | grep amf"
		output1, _ := edge.Run1(cmdStr1)
		if output1 != "" {
			cmdStr2 := "kubectl get po -nfree5gc | grep amf | awk '{print $1}' | xargs -i kubectl logs -n free5gc {} ephemeris --tail=4"
			// cmdStr2 := `kubectl get po -nfree5gc | grep amf | awk '{print $1}' | xargs -i kubectl exec -nfree5gc {} -c  ephemeris -- bash -c 'cat e.log'`
			output2, _ := edge.Run1(cmdStr2)
			fmt.Println(output2)
			c.String(200, "%v", output2)
		} else {
			c.String(200, "%v", "")
		}
	})

	// 控制面信令
	r.GET("/gnb", func(c *gin.Context) {
		cmdStr := `tail -n 3 /home/node/pcap/hap-gnb.txt| awk '{sub(/\..*/, "", $2); for(i=2;i<=NF;i++) printf $i (i==NF?RS:FS);}'`
		output, _ := edge.Run1(cmdStr)
		if strings.Contains(output, "tail") {
			output = ""
		}

		// 		output := `21:49:33.166517740 10.233.60.100 → 10.233.70.122 NGAP 134 NGSetupRequest
		// 21:49:33.168101239 10.233.70.122 → 10.233.60.100 NGAP 110 NGSetupResponse
		// 21:50:05.148967128 10.233.60.100 → 10.233.70.122 NGAP/NAS-5GS 138 InitialUEMessage, Registration request
		// 21:50:05.189552047 10.233.70.122 → 10.233.60.100 NGAP/NAS-5GS 146 DownlinkNASTransport, Authentication request
		// 21:50:05.192209962 10.233.60.100 → 10.233.70.122 NGAP/NAS-5GS 146 UplinkNASTransport, Authentication response
		// `
		jsonData := handleSignaling(output)
		// fmt.Println("json"+string(jsonData))
		c.String(200, "%v", jsonData)
	})

	// 用户面信令
	r.GET("/upf1", func(c *gin.Context) {
		cmdStr := `tail -n 3 /home/node/pcap/hap-upf.txt| awk '{sub(/\..*/, "", $2); for(i=2;i<=NF;i++) printf $i (i==NF?RS:FS);}'`
		output, _ := ubuntuDefaultString.Run1(cmdStr)
		if strings.Contains(output, "tail") {
			output = ""
		}
		// c.String(200, "%v", output)
		// output := `21:50:05.494218214 10.233.70.121 → 10.233.60.223 PFCP 58 PFCP Session Deletion Request
		// 21:50:05.495434675 10.233.60.223 → 10.233.70.121 PFCP 63 PFCP Session Deletion Response
		// 21:50:05.541607964 10.233.70.121 → 10.233.60.223 PFCP 362 PFCP Session Establishment Request
		// 21:50:05.542833419 10.233.60.223 → 10.233.70.121 PFCP 89 PFCP Session Establishment Response
		// `
		re := regexp.MustCompile("<[^>]+>")
		output = re.ReplaceAllString(output, "")
		jsonData := handleSignaling(output)
		c.String(200, "%v", jsonData)
	})
	r.GET("/upf2/pfcp", func(c *gin.Context) {
		cmdStr := `tail -n 3 /home/node/pcap/upf603-p.txt| awk '{sub(/\..*/, "", $2); for(i=2;i<=NF;i++) printf $i (i==NF?RS:FS);}'`
		output, _ := ubuntuDefaultString.Run1(cmdStr)
		if strings.Contains(output, "tail") {
			output = ""
		}

		// c.String(200, "%v", output)
		// output := `21:52:50.308635673 10.233.70.121 → 10.233.80.101 PFCP 58 PFCP Session Deletion Request
		// 21:52:50.309298101 10.233.80.101 → 10.233.70.121 PFCP 63 PFCP Session Deletion Response
		// 21:52:50.350054635 10.233.70.121 → 10.233.80.101 PFCP 362 PFCP Session Establishment Request
		// 21:52:50.350672795 10.233.80.101 → 10.233.70.121 PFCP 89 PFCP Session Establishment Response
		// `
		re := regexp.MustCompile("<[^>]+>")
		output = re.ReplaceAllString(output, "")
		jsonData := handleSignaling(output)
		// fmt.Println(jsonData)
		c.String(200, "%v", jsonData)
	})
	r.GET("/upf2/gtp", func(c *gin.Context) {
		cmdStr := `tail -n 3 /home/node/pcap/upf603-g.txt| awk '{sub(/\..*/, "", $2); for(i=2;i<=NF;i++) printf $i (i==NF?RS:FS);}'`
		output, _ := ubuntuDefaultString.Run1(cmdStr)
		if strings.Contains(output, "tail") {
			output = ""
		}
		// c.String(200, "%v", output)
		// output := `21:52:50.351521321    10.60.0.2 → 10.60.0.1    GTP <UDP> 126 7078 → 40824 Len=40
		// 21:52:50.351540847    10.60.0.2 → 10.60.0.1    GTP <UDP> 126 7078 → 40824 Len=40
		// 21:52:50.371259085    10.60.0.2 → 10.60.0.1    GTP <UDP> 121 7078 → 40824 Len=35
		// 21:52:50.371273282    10.60.0.2 → 10.60.0.1    GTP <UDP> 121 7078 → 40824 Len=35
		// `
		re := regexp.MustCompile("<[^>]+>")
		output = re.ReplaceAllString(output, "")
		jsonData := handleSignaling(output)
		c.String(200, "%v", jsonData)
	})
	r.GET("/weixing", func(c *gin.Context) {
		// 卫星数据结构
		// type WeixingEntry struct {
		// 	Path   		string `json:"path"`
		// 	Distance    string `json:"distance"`
		// }
		cmdStr := `powershell -command "& {Get-Content D:\weixingzu\files\View3\rightdown.csv}"`
		output, _ := weixingServer.Run1(cmdStr)
		// if strings.Contains(output, "tail") {
		// 	output = ""
		// }
		// lines := strings.Split(output, "\n")
		// // 使用正则表达式进行匹配
		// r := regexp.MustCompile(`(\d+),(\d+),(\d+),(\d+),(\d+),(\d+),([\d.]+)`)
		// var WeixingEntries []WeixingEntry
		// for _, line := range lines {
		// 	match := r.FindStringSubmatch(line)
		// 	if match != nil {
		// 		entry := WeixingEntry{
		// 			Path: fmt.Sprintf("%s,%s,%s,%s,%s,%s", match[1], match[2], match[3], match[4], match[5], match[6]),
		// 			Distance: match[7],
		// 		}
		// 		WeixingEntries = append(WeixingEntries, entry)
		// 	}
		// }
		// // 将解析后的数据转换为JSON格式
		// jsonData, err := json.Marshal(WeixingEntries)
		// if err != nil {
		// 	fmt.Println("Error marshaling JSON:", err)
		// }
		// // fmt.Println(jsonData)
		// c.String(200, "%v", string(jsonData))
		c.String(200, "%v", output)
	})
	r.GET("/weixing/show", func(c *gin.Context) {
		// 打开CSV文件
		file, err := os.Open("go_ssh/resources/weixingData/data0.csv")
		if err != nil {
			fmt.Println("Error opening CSV file:", err)
			return
		}
		defer file.Close()

		// 读取CSV内容
		reader := csv.NewReader(file)
		lines, err := reader.ReadAll()
		if err != nil {
			fmt.Println("Error reading CSV file:", err)
			return
		}

		// 转换为JSON格式
		var rawData []map[string]interface{}
		headers := lines[0]
		for _, line := range lines[1:] {
			entry := make(map[string]interface{})
			for i, value := range line {
				key := headers[i]
				entry[key] = value
			}
			rawData = append(rawData, entry)
		}

		// 返回JSON数据
		c.JSON(http.StatusOK, rawData)
	})

	r.GET("/weixing/next", func(c *gin.Context) {
		wd, err := os.Getwd()
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("Current working directory:", wd)
		// 打开CSV文件
		file, err := os.Open("go_ssh/resources/weixingData/rightdown.csv")
		if err != nil {
			fmt.Println("Error opening CSV file:", err)
			return
		}
		defer file.Close()

		// 读取CSV内容
		reader := csv.NewReader(file)
		lines, err := reader.ReadAll()
		if err != nil {
			fmt.Println("Error reading CSV file:", err)
			return
		}

		// 转换为JSON格式
		var rawData []map[string]interface{}
		headers := lines[0]
		for _, line := range lines[1:] {
			entry := make(map[string]interface{})
			for i, value := range line {
				key := headers[i]
				entry[key] = value
			}
			rawData = append(rawData, entry)
		}

		// 返回JSON数据
		c.JSON(http.StatusOK, rawData)
	})

	//绘制图像
	r.GET("/graph", func(c *gin.Context) {  
		// 读取CSV文件  
		times, values, err := readCSV("./go_ssh/resources/graph/graph1.csv")
		if err != nil {  
			c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})  
			return  
		}  
  
		// 创建响应数据  
		response := DataResponse{  
			Times:  times,  
			Values: values,  
		}  
		// fmt.Println(response)
		// 转换为JSON并发送给前端  
		c.JSON(http.StatusOK, response)  
	})

	// 启动一个web服务
	r.Run(":8081") // 可以从本地的127.0.0.1:8081访问，不填的话，默认是8080端口
}
